Datoteke I


Kalorije

Tina za vsak obrok, ki ga poje, zapiše njegovo kalorično vrednost (celo število). Vse te podatke hrani v datoteki: podatke vsakega dne zapiše v svojo vrstico, znotraj vrstice pa jih loči z vejico.

1. podnaloga

Sestavite funkcijo kalorijeNaDan(datoteka), ki kot parameter dobi ime vhodne datoteke in vrne seznam kalorij, ki jih je Tina dnevno zaužila.

Torej, za vsako vrstico v datoteki (ki predstavlja en dan) dodaj v seznam eno število, ki naj bo enako vsoti kalorij za tisti dan.

Uradna rešitev

def skupneKalorije(niz):
    '''sešteje cela števila v nizu, ki so ločena z vejico'''
    tabelaNizov = niz.split(',')
    skupnaVsota = 0
    for elt in tabelaNizov:
        skupnaVsota += int(elt) # ne pozabi pretvoriti niza v število!
    return skupnaVsota

def kalorijeNaDan(datoteka):
    '''Seznam kalorij, zaužitih na posamezni dan'''
    zaužiteKalorije = []
    for vrstica in open(datoteka):
        # uporabimo zgornjo funkcijo, ki "obdela" vrstico in seštejemo
        naTaDan = skupneKalorije(vrstica)
        zaužiteKalorije.append(naTaDan)
    return zaužiteKalorije

2. podnaloga

Sestavite funkcijo vsotaKalorij(vhod, izhod), ki kot argumenta dobi imeni dveh datotek: vhodno (ta vsebuje Tinine zapiske) in izhodno. Na izhodno datoteko naj za vsako vrstico v vhodni datoteki zapiše vsoto kaloričnih vrednosti zaužite hrane tistega dne. Vsako število v izhodni datoteki naj bo v svoji vrstici.

Uradna rešitev

def vsotaKalorij(vhod, izhod):
    '''za vsako vrstico v vhodni datoteki zapiše vsoto na izhodno datoteko'''
    piši = open(izhod, 'w')
    for vrstica in open(vhod):
        vsota = skupneKalorije(vrstica) # izračuna vsoto števil v vrstici
        piši.write(str(vsota) + '\n')
    piši.close()

3. podnaloga

Sestavite funkcijo povprecjeKalorij(vhod, izhod), ki kot argumenta dobi imeni dveh datotek: vhodno in izhodno. Na izhodno datoteko naj za vsako vrstico na vhodni datoteki zapiše zaporedno številko vrstice (vrstice se začno šteti z ena) ter povprečno kalorično vrednost obrokov, ki jih je Tina zaužila tisti dan, na dve decimalni mesti natančno. V zadnjo (dodatno) vrstico pa naj funkcija zapiše dnevno povprečje zaužitih kalorij (prav tako na dve decimalni mesti natančno).

Uradna rešitev

def vrniKalorije(niz):
    '''iz niza, v katerem so števila ločena z vejicami, vrne
       seznam teh celih števil.'''
    tabelaNizov = niz.split(',')
    izhTabela = []
    for elt in tabelaNizov:
        izhTabela.append(int(elt)) # dodamo število, ki ga dobimo iz niza
    return izhTabela
    # lahko bi vse skupaj napisali tudi v eni vrstici
    # return list(map(int, niz.split(',')))

def povprecjeKalorij(vhod,izhod):
    vsotaKalorij = 0
    steviloDni = 0
    piši = open(izhod, "w")
    for vrstica in open(vhod):
        obroki = vrniKalorije(vrstica)
        dnevniVnos = sum(obroki)
        steviloDni += 1
        vsotaKalorij += dnevniVnos
        print("{0} {1:.2f}".format(steviloDni, dnevniVnos / len(obroki)), file=piši)
    # še končni podatek o povprečju
    print("{0:.2f}".format(vsotaKalorij / steviloDni), file=piši)
    piši.close()

Delnice

1. podnaloga

V datoteki imamo zapisane podatke o vrednosti neke delnice. V vsaki vrstici je zapisan podatek v obliki

YYYY-MM-DD,vrednost

kjer je prvi podatek dan, drugi pa vrednost delnice na ta dan. Sestavite funkcijo preberi(ime_datoteke), ki kot parameter sprejme ime datoteke, vrne par nabor dveh seznamov, v prvem naj bodo datumi (kot nizi), v drugem pa vrednosti delnice (kot realna števila).

Uradna rešitev

def preberi(ime_datoteke):
    '''vrne par (nabor) dveh seznamov, v prvem so datumi
       (kot nizi), v drugem pa vrednosti delnice (kot realna števila).
    '''
    datumi = []
    vrednosti = []
    for vrstica in open(ime_datoteke,'r'):
        v = vrstica.strip().split(',') # prvi podatek je datum, drugi vrednost
        datumi.append(v[0]) # datum dodamo nespremenjen
        vrednosti.append(float(v[1]))
    return (datumi, vrednosti)

2. podnaloga

Logaritemski povratek delnice je definiran kot logaritem kvocienta vrednosti delnice za dva zaporedna dneva trgovanja. Zakaj je to uporabno Sestavite funkcijo povratek(imeDat), ki kot parameter sprejme ime datoteke z vrednostmi delnice in vrne seznam logaritemskih povratkov. Če je podana datoteka prazna ali pa vsebuje le en podatek, naj funkcija vrne prazen seznam.

Uradna rešitev

from math import log

def povratek(ime_datoteke):
    '''Vrne seznam logaritemskih popravkov'''
    datumi, vrednosti = preberi(ime_datoteke)
    povratki = []
    for i in range(1,len(vrednosti)): #začnemo pri drugem dnevu
        povratki.append(log(vrednosti[i]/vrednosti[i-1]))
    return povratki

3. podnaloga

Iz logaritemskih povratkov lahko razberemo, ali je vrednost delnice naraščala ali padala. Sestavite funkcijo trend(povratki), ki sprejme seznam logaritemskih povratkov in vrne niz pozitiven trend, če je v seznamu več pozitivnih vrednosti kot negativnih, sicer pa naj vrne negativen trend. Vrednosti 0 štejte k negativnim.

Uradna rešitev

def trend(povratki):
    '''Vrne niz "pozitiven trend", če je v seznamu logaritemskih povratkov več pozitivnih vrednosti kot negativnih,
       sicer pa "negativen trend"'''
    poz = 0
    neg = 0
    for x in povratki:
        if x > 0:
            poz += 1
        else:
            neg += 1
    if poz > neg:
        return 'pozitiven trend'
    else:
        return 'negativen trend'

4. podnaloga

Letna volatilnost delnice (Volatilnost ali nihajnost označuje, koliko je statistično verjetno, da cena delnice v kratkem času močneje zraste ali pade) je definirana kot večkratnik standardnega odklona logaritemskega povratka: $$\sigma^2 = \frac{252}{n}\sum_{i=1}^n (x_i-\mu)^2,$$ kjer je $\mu$ povprečna vrednost logaritemskih povratkov, $x_i$ so posamezni logaritemski povratki, $n$ je število logaritemskih povratkov, 252 pa predstavlja število trgovalnih dni v letu. Sestavite funkcijo volatilnost(ime_datoteke), ki iz datoteke prebere vrednosti delnice in vrne njeno letno volatilnost $\sigma$.

Uradna rešitev

from math import sqrt
def volatilnost(ime):
    ''' iz datoteke prebere vrednosti delnice in vrne njeno letno volatilnost'''
    p = povratek(ime)
    n = len(p)
    mu = sum(p)/n # povprečna vrednost logaritemskih povratkov
    s2 = 0 
    for x in p:
        s2 += (x-mu)**2
    return sqrt(252 * s2/n)

Datoteke s HTML

1. podnaloga

Sestavite funkcijo html2txt(vhod, izhod), ki bo vsebino datoteke z imenom vhod prepisala v datoteko z imenom izhod, pri tem pa odstranila vse značke. Vemo, da je datoteka HTML sestavljena prav!

Značke se začnejo z znakom < in končajo z znakom >. Pozor: Začetek in konec značke nista nujno v isti vrstici. Takrat se vrstica nadaljuje! Prav tako ima lahko značka lastnosti, npr. značka a ima lastnost href

<a href = "kk.htm">

Na primer, če je v datoteki vreme.html zapisano:

<h1>Napoved vremena</h1>
<p>Jutri bo <i><b>lepo</b></i> vreme.
Več o vremenu preberite <a
href="napoved.html">tukaj</a>.</p>

bo po klicu html2txt('vreme.html', 'vreme.txt') v datoteki vreme.txt zapisano (pozor na tretjo vrstico!):

Napoved vremena
Jutri bo lepo vreme.
Več o vremenu preberite tukaj.

Uradna rešitev

def html2txt(vhod, izhod):
    ''' Funkcija vsebino datoteke z imenom vhod
    prepiše v datoteko z imenom izhod, pri tem pa
    odstrani vse značke za HTML. '''
    html = open(vhod)
    txt = open(izhod, 'w')
    znotrajZnačke = False # ali se nahajamo v notranjosti
    for vrstica in html:
        izhodnaVrstica = ''
        for znak in vrstica:
            if znak in '<>': # če smo naleteli na začetek ali na konec značke
                znotrajZnačke = not znotrajZnačke
            else: # gre za nek drug znak
                if not znotrajZnačke : # če nismo v znački, znak dodamo
                    izhodnaVrstica += znak
        txt.write(izhodnaVrstica)
    html.close()
    txt.close()

2. podnaloga

Sestavite funkcijo tabela(vhod, izhod), ki bo podatke iz vhodne datoteke zapisala v obliki HTML tabele v izhodno datoteko.

V vhodni datoteki so podatki shranjeni po vrsticah ter ločeni z vejicami. Na primer, če je v datoteki tabela.txt zapisano:

ena,dva,tri
17,52,49.4,6
abc,xyz

bo po klicu tabela('tabela.txt', 'tabela.html') v datoteki tabela.html:

<table>
  <tr>
    <td>ena</td>
    <td>dva</td>
    <td>tri</td>
  </tr>
  <tr>
    <td>17</td>
    <td>52</td>
    <td>49.4</td>
    <td>6</td>
  </tr>
  <tr>
    <td>abc</td>
    <td>xyz</td>
  </tr>
</table>

Pozor: Pazi na zamik (število presledkov na začetku vrstic) v izhodni datoteki.

Uradna rešitev

def tabela(ime_vhodne, ime_izhodne):
    ''' zapis podatkov iz CSV datoteko v datoteko HTML v obliki tabele'''

    # naučimo se uporabljati stavek with! Tu ni uporabe metode close!
    with open(ime_vhodne) as vhodna:
        with open(ime_izhodne, 'w') as izhodna:
            print('<table>', file=izhodna) # začetek tabele
            for vrstica in vhodna:
                print('  <tr>', file=izhodna) # vska vrstica se začne z glavo
                vrstica = vrstica.strip() # znebimo se uvodnih in končnih 'belih' znakov
                podatki = vrstica.strip().split(',') #ločilni znak med podatki je vejica
                for podatek in podatki: # posamezni stolpci
                    print('    <td>{0}</td>'.format(podatek), file=izhodna)
                print('  </tr>', file=izhodna) # konec vrstice
            print('</table>', file=izhodna) # konec tabele

3. podnaloga

Sestavite funkcijo seznami(vhod, izhod), ki bo podatke iz vhodne datoteke zapisala v izhodno datoteko v obliki neurejenega seznama. V vhodni datoteki se vrstice seznamov začnejo z zvezdico.

Na primer, če je v datoteki seznami.txt zapisano:

V trgovini moram kupiti:
* jajca,
* kruh,
* moko.
Na poti nazaj moram:
* obiskati sosedo.

bo po klicu seznami('seznami.txt', 'seznami.html') v datoteki seznami.html:

V trgovini moram kupiti:
<ul>
  <li>jajca,</li>
  <li>kruh,</li>
  <li>moko.</li>
</ul>
Na poti nazaj moram:
<ul>
  <li>obiskati sosedo.</li>
</ul>

Uradna rešitev

def seznami(ime_vhodne, ime_izhodne):
    '''Seznam na tekstovni datoteki prepišimo kot naštevni seznam v HTML'''
    seznam = False # ali smo znotraj obstoječega seznama 
    vhodna = open(ime_vhodne)
    izhodna = open(ime_izhodne, 'w')
    for vrstica in vhodna:
        if vrstica[0] == '*': # z * so označeni elementi seznama 
            if not seznam: # gre za nov seznam, zato ga ustvarimo!
                print('<ul>', file=izhodna)
                seznam = True
            print('  <li>{0}</li>'.format(vrstica[2:-1]), file=izhodna) # znebimo se uvodne * s presledkom, in \n s konca
        else: #'navadna vrstica' 
            if seznam: # je potrebno zaključiti seznam?
                print('</ul>', file=izhodna)
                seznam = False
            print(vrstica, file=izhodna, end='')
    if seznam: print('</ul>', file=izhodna) # če je zadnji seznam šel do konca datoteke!
    vhodna.close()
    izhodna.close()

4. podnaloga

Sestavite funkcijo gnezdeni_seznami(vhod, izhod), ki bo podatke iz vhodne datoteke zapisala v izhodno datoteko v obliki neurejenega gnezdenega seznama. V vhodni datoteki je vsak element seznama v svoji vrstici, zamik pred elementom pa določa, kako globoko je element gnezden.

Na primer, če je v datoteki seznami.txt zapisano:

živali
  sesalci
    slon
  ptiči
    sinička
rastline
  sobne rastline
    difenbahija

bo po klicu gnezdeni_seznami('seznami.txt', 'seznami.html') v datoteki seznami.html zapisano:

<ul>
  <li>živali
    <ul>
      <li>sesalci
        <ul>
          <li>slon
        </ul>
      <li>ptiči
        <ul>
          <li>sinička
        </ul>
    </ul>
  <li>rastline
    <ul>
      <li>sobne rastline
        <ul>
          <li>difenbahija
        </ul>
    </ul>
</ul>

Značk <li> ne zapirajte.

Uradna rešitev

def gnezdeni_seznami(ime_vhodne, ime_izhodne):
    '''iz "navadnega" gnezdenega seznama naredimo tak seznam v HTML'''
    nivo = 0
    zamik = 2
    # naučimo se uporabljati stavek with! Tu ni uporabe metode close!
    with open(ime_vhodne) as vhodna:
        with open(ime_izhodne, 'w') as izhodna:
            for vrstica in vhodna:
                # izračunaj na katerem nivoju sem
                # poiskati moramo prvi znak, ki ni presledek
                prviZnak = 0
                for i in range(len(vrstica)):
                    if vrstica[i] != ' ':
                        break # našli smo ga
                    prviZnak += 1 # ga še ni
                n = prviZnak // zamik + 1 # račun nivoja
                vrstica = vrstica.strip() #sedaj se lahko znebimo začetnih in končnih 'belih znakov'
                if n > nivo: # je potrebno začetni novo gnezdenje?
                    print(2 * zamik * nivo * ' ' + '<ul>', file=izhodna, sep="")
                    nivo += 1
                while n < nivo: # končamo gnezdenje
                    nivo -= 1
                    print(2 * zamik * nivo * ' ' + '</ul>', file=izhodna, sep="")
                print((2 * zamik * nivo - zamik) * ' ' + '<li>', vrstica, file=izhodna, sep="")
            while nivo > 0: # še končen zaključek gnezdenja
                nivo -= 1
                print(2 * zamik * nivo * ' ' + '</ul>', file=izhodna, sep="")

Golf

Na vsakem zanimivem igrišču za golf so ovire: jezero, pesek, ...

Jezero je krog, podan kot trojica (x,y,r). Pesek je pravokotnik, podan kot četverica(x1,y1,x2,y2). Predpostaviš lahko, da so to po vrsti koordinate levega spodnjega in desnega zgornjega oglišča. Vse koordinate računamo na tri decimalke (round(x, 3))

1. podnaloga

Na datoteki imamo zapisane podatke o posameznih udarcih v obliki polarnih koordinat. V vsaki vrstici sta zapisani celi števili r in f, ločeni s presledkom. Napišite metodo datotekaPolozajev(vhod, izhod), ki naj datoteko prebere in v tvori novo datoteko tako, da je v vsaki vrstici zapisan njen trenutni položaj (v obliki decimalnih števil, zaokroženih na 3 decimalna mesta) in ločenih s presledkom. V ta namen uporabite formatiranje s pomočjo "{0:.3f}".format(x) Začetni položaj naj bo v točki (0,0).

Uradna rešitev

from math import *

def datotekaPolozajev(vhod, izhod):
    '''Iz seznama udarcev, podanih v polarnih koordinatah, na datoteko zapiše
       kartezične koordinate položaja točk'''
    x,y = 0,0
    g = open(izhod, "w") 
    for vrstica in open(vhod):
        polarnekoordinate = vrstica.strip('\n').split(' ')
        r = int(polarnekoordinate[0])
        fi = int(polarnekoordinate[1])
        x += r * cos(fi * pi / 180)
        y += r * sin(fi * pi / 180)
        print("{0:.3f}".format(x), "{0:.3f}".format(y), file=g)
    g.close()

2. podnaloga

Podan je seznam položajev žogic po posameznem udarcu in seznam, katerega vsak element je nabor, ki podaja jezero ali pesek. Napišite metodo seIzogne(pot, ovire), ki pove, ali se pot v celoti izogne oviram. Pazi: jezero je podano z naborom treh, pesek pa z naborom štirih števil.

Najprej napišite metodi jeVJezeru(zogica, jezero) in jeVPesku(zogica, pesek), ki povesta, ali je žogica v jezeru ali v pesku. Žogica je podana kot par (x,y), torej "nima dimenzije".

Uradna rešitev

def jeVJezeru(zogica, jezero):
    '''Ali je zogica znotraj jezera '''
    (x0,y0) = zogica 
    (x,y,r) = jezero # okroglo jezero
    return round((x-x0)**2 + (y-y0)**2,3) <= round(r**2, 3)

def jeVPesku(zogica, pesek):
    '''Ali je zogica znotraj peska '''
    (x0,y0) = zogica
    (xmin,ymin,xmax,ymax) = pesek # prakokotna peščena ovira
    return (xmin <= x0 <= xmax) and (ymin <= y0 <= ymax)

def seIzogne(pot, ovire):
    '''Ali se žogice, katerih položaji so podani v seznamu pot
       izogne vsem oviram, podanih v seznamu ovire'''
    for tocka in pot:
        # za vsak položaj preverimo, če smo naleteli na kakšno oviro
        for ovira in ovire:
            if (len(ovira)==3 and jeVJezeru(tocka, ovira)): # žogica se znajde v jezeru
                return False
            if (len(ovira)==4 and jeVPesku(tocka, ovira)): # žogica se znajde v peščeni oviri
                return False
    return True

3. podnaloga

Napišite metodo kjeJeZogica(datoteka, zacetek, ovire), ki vrne vektor od začenega do končnega položaja ali None, če žogica kdaj vmes pade v oviro. Posamezni udarci so v polarnih koordinatah zapisani na datoteko, začetek pa je podan kot par (x,y).

Uradna rešitev

def kjeJeZogica(datoteka, zacetek, ovire):
    '''Glede na seznam udarcev, podanem na datoteki datoteka,
       seznama ovir (seznam naborov) in začetnega položaja žogice
       ugotovi vektor od začetnega do končnega položaja žogice.
       Če žogica pristane v oviri, vrni None'''
    x,y = zacetek
    pot = []
    pot.append((x,y))
    # sestavimo seznam položajev žogice
    for vrstica in open(datoteka):
        polarnekoordinate = vrstica.strip('\n').split(' ')
        r = int(polarnekoordinate[0])
        fi = int(polarnekoordinate[1])
        x += r * cos(fi * pi / 180)
        y += r * sin(fi * pi / 180)
        pot.append((round(x,3),round(y,3)))
    # na koncu je žogica v (x, y)
    # uporabimo funkcijo prejšnje naloge
    if not seIzogne(pot, ovire):
        return None
    else:
        return (round(x-zacetek[0], 3),round(y-zacetek[0],3))